package com.atlassian.bamboo.license;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.atlassian.bamboo.setup.BootstrapManager;
import com.atlassian.bamboo.util.BuildUtils;
import com.atlassian.config.ConfigurationException;
import com.atlassian.extras.api.AtlassianLicense;
import com.atlassian.extras.api.LicenseEdition;
import com.atlassian.extras.api.LicenseType;
import com.atlassian.extras.api.Product;
import com.atlassian.extras.api.bamboo.BambooLicense;
import com.atlassian.extras.core.LicenseManagerFactory;
import com.atlassian.license.LicensePair;

public class BambooLicenseManagerImpl implements BambooLicenseManager {
	private static final Logger log = Logger
			.getLogger(BambooLicenseManagerImpl.class);
	public static final String BAMBOO_LICENSE_KEY = "Bamboo";
	private final BootstrapManager bootstrapManager;
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private final Map<String, String> legacyLicenseStrings = new ConcurrentHashMap(1);

	public BambooLicenseManagerImpl(@NotNull BootstrapManager bootstrapManager) {
		this.bootstrapManager = bootstrapManager;
	}

	@Nullable
	public BambooLicense getLicense() {
		String licenseString = getLicenseString();
		if (licenseString != null) {
			AtlassianLicense atlassianLicense = LicenseManagerFactory
					.getLicenseManager().getLicense(licenseString);
			return (BambooLicense) atlassianLicense
					.getProductLicense(Product.BAMBOO);
		}

		return null;
	}

	@Nullable
	private String getLicenseString() {
		String licenseString = (String) this.bootstrapManager
				.getProperty("license.string");
		if (licenseString == null) {
			String message = (String) this.bootstrapManager
					.getProperty("license.message");
			String hash = (String) this.bootstrapManager
					.getProperty("license.hash");

			if ((hash != null) && (message != null)) {
				String key = hash + message;
				licenseString = (String) this.legacyLicenseStrings.get(key);
				if (licenseString == null) {
					try {
						LicensePair pair = new LicensePair(message, hash);
						licenseString = pair.getOriginalLicenseString();

						this.legacyLicenseStrings.put(key, licenseString);
					} catch (com.atlassian.license.LicenseException e) {
						log.error(
								"Could not load legacy license and no v2 license exists",
								e);
					}
				}
			}
		}
		return licenseString;
	}

	public void setLicense(String license) {
		this.bootstrapManager.removeProperty("license.hash");
		this.bootstrapManager.removeProperty("license.message");
		this.bootstrapManager.setProperty("license.string", license);
		try {
			this.bootstrapManager.save();
		} catch (ConfigurationException e) {
			log.error(e, e);
		}
	}

	public boolean authenticateLicense(String license) {
		try {
			AtlassianLicense atlassianLicense = LicenseManagerFactory
					.getLicenseManager().getLicense(license);
			BambooLicense bambooLicense = (BambooLicense) atlassianLicense
					.getProductLicense(Product.BAMBOO);
			return (bambooLicense != null) && (!bambooLicense.isExpired())
					&& (!isMaintenanceExpiredForBuild(bambooLicense));
		} catch (com.atlassian.extras.common.LicenseException e) {
			return false;
		} catch (Exception e) {
		}
		return false;
	}

	public boolean isLicenseValid() {
		BambooLicense license = getLicense();
		return (license != null) && (!license.isExpired());
	}

	private boolean isMaintenanceExpiredForBuild(BambooLicense license) {
		return (license != null)
				&& (license.getMaintenanceExpiryDate().getTime() < getBuildDate()
						.getTime());
	}

	protected Date getBuildDate() {
		return BuildUtils.getCurrentBuildDate();
	}

	public boolean isMaintenanceExpiredForBuild() {
		BambooLicense license = getLicense();
		return isMaintenanceExpiredForBuild(license);
	}

	public int getAllowedNumberOfRemoteAgents() {
		BambooLicense license = getLicense();
		if (license != null) {
			return license.getMaximumNumberOfRemoteAgents();
		}
		return 0;
	}

	public int getAllowedNumberOfLocalAgents() {
		BambooLicense license = getLicense();
		if (license != null) {
			return license.getMaximumNumberOfLocalAgents();
		}
		return -1;
	}

	public int getAllowedNumberOfPlans() {
		BambooLicense license = getLicense();
		return getAllowedNumberOfPlans(license);
	}

	public int getAllowedNumberOfPlans(String licenseString) {
		AtlassianLicense atlassianLicense = LicenseManagerFactory
				.getLicenseManager().getLicense(licenseString);
		BambooLicense license = (BambooLicense) atlassianLicense
				.getProductLicense(Product.BAMBOO);
		return getAllowedNumberOfPlans(license);
	}

	private int getAllowedNumberOfPlans(BambooLicense license) {
		if (license != null) {
			return license.getMaximumNumberOfPlans();
		}
		return -1;
	}

	public boolean isStarter() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.STARTER, license));
	}

	public boolean isBasicEdition() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseEdition(LicenseEdition.BASIC, license));
	}

	public boolean isEvaluation() {
		BambooLicense license = getLicense();
		return (license != null) && (license.isEvaluation());
	}

	public boolean isAcademic() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.ACADEMIC, license));
	}

	public boolean isDemonstration() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.DEMONSTRATION, license));
	}

	public boolean isDeveloper() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.DEVELOPER, license));
	}

	public boolean isCommunity() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.COMMUNITY, license));
	}

	public boolean isOpenSource() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.OPEN_SOURCE, license));
	}

	public boolean isCommercial() {
		BambooLicense license = getLicense();
		return (license != null)
				&& (isLicenseType(LicenseType.COMMERCIAL, license));
	}

	private boolean isLicenseEdition(@NotNull LicenseEdition edition,
			@NotNull BambooLicense license) {
		return edition.equals(license.getLicenseEdition());
	}

	private boolean isLicenseType(@NotNull LicenseType type,
			@NotNull BambooLicense license) {
		return type.equals(license.getLicenseType());
	}
}